/***************************************************************************
 * Open Object Oriented ANSI C                                             *
 ***************************************************************************
 * Code given under the terms of GNU General Public Licence (GPLv3)        *
 * and without any waranties of any kind including but not limitative to   *
 * waranties on merchandability or any particular applications fitness.    *
 * For more information on GNU/GPL go on :                                 *
 * "http://www.gnu.org/copyleft/gpl.html"                                  *
 *                                                                         *
 * You are allowed to use it for any purposes in the terms of GNU/GPLv3    *
 * (or more).                                                              *
 * This text MUST stay in state on copyed sources (or sources using it)    *
 * and must not be altered.                                                *
 * You are allowed to add your name at the end of the Copylefs list.       *
 ***************************************************************************
 * Copylefts List :                                                        *
 ***************************************************************************
 * 2010-03-20 Patrick PIGNOL <pignol_patrick@hotmail.com> (Original)       *
 * (Type your name here if needed)                                         *
 ***************************************************************************/
#include <stdlib.h>
#include <signal.h>
#include "Mem.h"
#include "Class.h"
#include "Pipe.h"
#include "ExceptionManager.h"

static PipeVirtualTable* PipeVirtualTableInstance = 0;

Pipe* PipeNew(unsigned long int pArgsCount, va_list* pParameters)
{
    Pipe* this;
    if(!(this = (Pipe*) malloc(sizeof(Pipe))))
    {
        raise(SIGABRT);
    }
    this->VirtualTable = PipeInitialize(this, pArgsCount, pParameters);
    this->Constructor = PipeConstructor;
    this->Destructor = PipeDestructor;
    this->Clone = PipeClone;
    this->Push = PipePush;
    this->Pop = PipePop;
    this->Count = PipeCount;
    this->Constructor(this, pArgsCount, pParameters);
    return this;
}

PipeVirtualTable* PipeInitialize(Pipe* this, unsigned long int pArgsCount, va_list* pParameters)
{
    if(!PipeVirtualTableInstance)
    {
        PipeVirtualTableInstance = (PipeVirtualTable*) malloc(sizeof(PipeVirtualTable));
        if(!PipeVirtualTableInstance)
        {
            raise(SIGABRT); /* this = 0 => error*/
        }

        PipeVirtualTableInstance->TypeID = PIPE_TYPEID;

        PipeVirtualTableInstance->Interface = 0;

        PipeVirtualTableInstance->AncestorTable = ClassInitialize((Class*)this, pArgsCount, pParameters);

        PipeVirtualTableInstance->ReferenceCount = 0;

        PipeVirtualTableInstance->new = PipeNew;
        PipeVirtualTableInstance->Initialize = PipeInitialize;
        PipeVirtualTableInstance->Garbage = (void(*)(Pipe*))PipeVirtualTableInstance->AncestorTable->Garbage;
        PipeVirtualTableInstance->TypeOf = (unsigned long int (*)(Pipe*))PipeVirtualTableInstance->AncestorTable->TypeOf;
        PipeVirtualTableInstance->IsSameTypeThanTypeID = (bool (*)(Pipe*, unsigned long int))PipeVirtualTableInstance->AncestorTable->IsSameTypeThanTypeID;
        PipeVirtualTableInstance->IsKindOfTypeID = (bool (*)(Pipe* this, unsigned long int))PipeVirtualTableInstance->AncestorTable->IsKindOfTypeID;
        PipeVirtualTableInstance->IsSameTypeThan = (bool (*)(Pipe* this, Class*))PipeVirtualTableInstance->AncestorTable->IsSameTypeThan;
        PipeVirtualTableInstance->IsKindOf = (bool (*)(Pipe* this, Class*))PipeVirtualTableInstance->AncestorTable->IsKindOf;
    }
    PipeVirtualTableInstance->ReferenceCount++;
    return PipeVirtualTableInstance;
}

void PipeConstructor(Pipe* this, unsigned long int pArgsCount, va_list* pParameters)
{
    this->aPipe = 0;
    this->aCount = 0;
}

void PipeDestructor(Pipe* this)
{
    this->Clone = 0; /* Avoid cloning on destruction.*/

    while(this->aPipe)
    {
        this->Pop(this);
    }
}

Pipe* PipeClone(Pipe* this)
{
    Pipe* vClone = 0;
    unsigned long int vIndex = 0;
    if(this)
    {
        if(this)
        {
            vClone = (Pipe*) new((void*(*)(unsigned long int, va_list*))this->VirtualTable->new, 0);
            vClone->aPipe = (Class**) calloc((this->aCount), sizeof(Class*));
            for(vIndex = 0; vIndex < this->aCount; vIndex++)
            {
                vClone->aPipe[vIndex] = this->aPipe[vIndex];
            }
            vClone->aCount = this->aCount;
        }
    }
    return vClone;
}

void PipePush(Pipe* this, Class* pObject)
{
    if(!this->aPipe)
    {
        this->aPipe = (Class**) calloc((this->aCount+1), sizeof(Class*));
    }
    else
    {
        this->aPipe = (Class**) realloc(this->aPipe, (sizeof(Class*)) * (this->aCount + 1));
    }
    if(this->aPipe)
    {
        this->aPipe[this->aCount] = pObject;
        this->aCount++;
    }
}

Class* PipePop(Pipe* this)
{
    Class* vResult = 0;
    unsigned long vIndex;
    if(this->aPipe)
    {
        vResult = this->aPipe[0];
        this->aCount--;
        if(!this->aCount)
        {
            free(this->aPipe);
            this->aPipe = 0;
        }
        else
        {
            for(vIndex = 0; vIndex < this->aCount; vIndex++)
            {
                this->aPipe[vIndex] = this->aPipe[vIndex + 1];
            }
            this->aPipe[this->aCount] = 0;
            this->aPipe = (Class**) realloc(this->aPipe, (sizeof(Class*)) * (this->aCount));
        }
    }
    return vResult;
}

unsigned long int PipeCount(Pipe* this)
{
    return this->aCount;
}
